home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / rumors.c < prev    next >
C/C++ Source or Header  |  1993-01-21  |  9KB  |  321 lines

  1. /*    SCCS Id: @(#)rumors.c    3.1    92/12/05    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6.  
  7. /*    [note: this comment is fairly old, but still accurate for 3.1]
  8.  * Rumors have been entirely rewritten to speed up the access.  This is
  9.  * essential when working from floppies.  Using fseek() the way that's done
  10.  * here means rumors following longer rumors are output more often than those
  11.  * following shorter rumors.  Also, you may see the same rumor more than once
  12.  * in a particular game (although the odds are highly against it), but
  13.  * this also happens with real fortune cookies.  -dgk
  14.  */
  15.  
  16. /*    3.1
  17.  * The rumors file consists of a "do not edit" line, a hexadecimal number
  18.  * giving the number of bytes of useful/true rumors, followed by those
  19.  * true rumors (one per line), followed by the useless/false/misleading/cute
  20.  * rumors (also one per line).  Number of bytes of untrue rumors is derived
  21.  * via fseek(EOF)+ftell().
  22.  *
  23.  * The oracles file consists of a "do not edit" comment, a decimal count N
  24.  * and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
  25.  * records, separated by "---" lines.  The first oracle is a special case,
  26.  * and placed there by 'makedefs'.
  27.  */
  28.  
  29. #ifndef SEEK_SET
  30. # define SEEK_SET 0
  31. #endif
  32. #ifndef SEEK_CUR
  33. # define SEEK_CUR 1
  34. #endif
  35. #ifndef SEEK_END    /* aka SEEK_EOF */
  36. # define SEEK_END 2
  37. #endif
  38.  
  39. static void FDECL(init_rumors, (FILE *));
  40. static void FDECL(init_oracles, (FILE *));
  41. static void FDECL(outoracle, (BOOLEAN_P));
  42.  
  43. static long true_rumor_start,  true_rumor_size,  true_rumor_end,
  44.         false_rumor_start, false_rumor_size, false_rumor_end;
  45. static int oracle_flg = 0;  /* -1=>don't use, 0=>need init, 1=>init done */
  46. static unsigned oracle_cnt = 0;
  47. static long *oracle_loc = 0;
  48.  
  49. static void
  50. init_rumors(fp)
  51. FILE *fp;
  52. {
  53.     char line[BUFSZ];
  54.  
  55.     (void) fgets(line, sizeof line, fp);    /* skip "don't edit" comment */
  56.     if (fscanf(fp, "%6lx\n", &true_rumor_size) == 1 &&
  57.         true_rumor_size > 0L) {
  58.         (void) fseek(fp, 0L, SEEK_CUR);
  59.         true_rumor_start  = ftell(fp);
  60.         true_rumor_end    = true_rumor_start + true_rumor_size;
  61.         (void) fseek(fp, 0L, SEEK_END);
  62.         false_rumor_end   = ftell(fp);
  63.         false_rumor_start = true_rumor_end;    /* ok, so it's redundant... */
  64.         false_rumor_size  = false_rumor_end - false_rumor_start;
  65.     } else
  66.         true_rumor_size = -1L;    /* init failed */
  67. }
  68.  
  69. char *
  70. getrumor(truth)
  71. int truth; /* 1=true, -1=false, 0=either */
  72. {
  73.     static char rumor_buf[COLNO + 28];
  74.     FILE    *rumors;
  75.     long tidbit, beginning;
  76.     char    *endp, line[sizeof rumor_buf];
  77.  
  78.     rumor_buf[0] = '\0';
  79.     if (true_rumor_size < 0L)    /* we couldn't open RUMORFILE */
  80.         return rumor_buf;
  81.  
  82.     rumors = fopen_datafile(RUMORFILE, "r");
  83.  
  84.     if (rumors) {
  85.         if (true_rumor_size == 0L) {    /* if this is 1st outrumor() */
  86.             init_rumors(rumors);
  87.             if (true_rumor_size < 0L) {    /* init failed */
  88.             Sprintf(rumor_buf, "Error reading \"%.80s\".",
  89.                 RUMORFILE);
  90.             return rumor_buf;
  91.             }
  92.         }
  93.         /*
  94.          *    input:      1    0   -1
  95.          *     rn2 \ +1  2=T  1=T  0=F
  96.          *     adj./ +0  1=T  0=F -1=F
  97.          */
  98.         switch (truth += rn2(2)) {
  99.           case  2:    /*(might let a bogus input arg sneak thru)*/
  100.           case  1:  beginning = true_rumor_start;
  101.                 tidbit = Rand() % true_rumor_size;
  102.             break;
  103.           case  0:    /* once here, 0 => false rather than "either"*/
  104.           case -1:  beginning = false_rumor_start;
  105.                 tidbit = Rand() % false_rumor_size;
  106.             break;
  107.           default:
  108.                 impossible("strange truth value for rumor");
  109.             return strcpy(rumor_buf, "Oops...");
  110.         }
  111.         (void) fseek(rumors, beginning + tidbit, SEEK_SET);
  112.         (void) fgets(line, sizeof line, rumors);
  113.         if (!fgets(line, sizeof line, rumors) ||
  114.             (truth > 0 && ftell(rumors) > true_rumor_end)) {
  115.             /* reached end of rumors -- go back to beginning */
  116.             (void) fseek(rumors, beginning, SEEK_SET);
  117.             (void) fgets(line, sizeof line, rumors);
  118.         }
  119.         if ((endp = index(line, '\n')) != 0) *endp = 0;
  120.         Strcat(rumor_buf, xcrypt(line));
  121.         (void) fclose(rumors);
  122.         exercise(A_WIS, (truth > 0));
  123.     } else {
  124.         pline("Can't open rumors file!");
  125.         true_rumor_size = -1;    /* don't try to open it again */
  126.     }
  127.     return rumor_buf;
  128. }
  129.  
  130. void
  131. outrumor(truth, cookie)
  132. int truth; /* 1=true, -1=false, 0=either */
  133. boolean cookie;
  134. {
  135.     static const char fortune_msg[] =
  136.         "This cookie has a scrap of paper inside.";
  137.     const char *line;
  138.  
  139.     if (cookie && Blind) {
  140.         pline(fortune_msg);
  141.         pline("What a pity that you cannot read it!");
  142.         return;
  143.     }
  144.     line = getrumor(truth);
  145.     if (!*line)
  146.         line = "NetHack rumors file closed for renovation.";
  147.     if (cookie) {
  148.         pline(fortune_msg);
  149.         pline("It reads:");
  150.         pline("%s", line);
  151.     } else {    /* if the Oracle is the only alternative */
  152.         pline("True to her word, the Oracle %ssays: ",
  153.         (!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " :
  154.         (rn2(2) ? "nonchalantly " : ""))));
  155.         verbalize("%s", line);
  156.         exercise(A_WIS, TRUE);
  157.     }
  158. }
  159.  
  160. static void
  161. init_oracles(fp)
  162. FILE *fp;
  163. {
  164.     register int i;
  165.     char line[BUFSZ];
  166.     int cnt = 0;
  167.  
  168.     /* this assumes we're only called once */
  169.     (void) fgets(line, sizeof line, fp);    /* skip "don't edit" comment */
  170.     if (fscanf(fp, "%5d", &cnt) == 1 && cnt > 0) {
  171.         oracle_cnt = (unsigned) cnt;
  172.         oracle_loc = (long *) alloc(cnt * sizeof (long));
  173.         for (i = 0; i < cnt; i++)
  174.         (void) fscanf(fp, "%5lx", &oracle_loc[i]);
  175.     }
  176.     return;
  177. }
  178.  
  179. void
  180. save_oracles(fd)
  181. int fd;
  182. {
  183.     bwrite(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt);
  184.     if (oracle_cnt)
  185.         bwrite(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long));
  186. }
  187.  
  188. void
  189. restore_oracles(fd)
  190. int fd;
  191. {
  192.     mread(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt);
  193.     if (oracle_cnt) {
  194.         oracle_loc = (long *) alloc(oracle_cnt * sizeof (long));
  195.         mread(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long));
  196.         oracle_flg = 1;    /* no need to call init_oracles() */
  197.     }
  198. }
  199.  
  200. static void
  201. outoracle(special)
  202. boolean special;
  203. {
  204.     char    line[COLNO];
  205.     char    *endp;
  206.     FILE    *oracles;
  207.     int oracle_idx;
  208.  
  209.     if(oracle_flg < 0 ||            /* couldn't open ORACLEFILE */
  210.        (oracle_flg > 0 && oracle_cnt == 0))    /* oracles already exhausted */
  211.         return;
  212.  
  213.     oracles = fopen_datafile(ORACLEFILE, "r");
  214.  
  215.     if (oracles) {
  216.         winid tmpwin;
  217.         if (oracle_flg == 0) {    /* if this is the first outoracle() */
  218.             init_oracles(oracles);
  219.             oracle_flg = 1;
  220.             if (oracle_cnt == 0) return;
  221.         }
  222.         /* oracle_loc[0] is the special oracle;        */
  223.         /* oracle_loc[1..oracle_cnt-1] are normal ones    */
  224.         if (oracle_cnt <= 1 && !special) return;  /*(shouldn't happen)*/
  225.         oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1);
  226.         (void) fseek(oracles, oracle_loc[oracle_idx], SEEK_SET);
  227.         if (!special) oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt];
  228.  
  229.         tmpwin = create_nhwindow(NHW_TEXT);
  230.         putstr(tmpwin, 0, special ?
  231.               "The Oracle scornfully takes all your money and says:" :
  232.               "The Oracle meditates for a moment and then intones:");
  233.         putstr(tmpwin, 0, "");
  234.  
  235.         while (fgets(line, COLNO, oracles) && strcmp(line,"---\n")) {
  236.             if ((endp = index(line, '\n')) != 0) *endp = 0;
  237.             putstr(tmpwin, 0, xcrypt(line));
  238.         }
  239.         display_nhwindow(tmpwin, TRUE);
  240.         destroy_nhwindow(tmpwin);
  241.         (void) fclose(oracles);
  242.     } else {
  243.         pline("Can't open oracles file!");
  244.         oracle_flg = -1;    /* don't try to open it again */
  245.     }
  246. }
  247.  
  248. int
  249. doconsult(oracl)
  250. register struct monst *oracl;
  251. {
  252.     int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel;
  253.     int add_xpts;
  254.     char qbuf[QBUFSZ];
  255.  
  256.     multi = 0;
  257.  
  258.     if (!oracl) {
  259.         pline("There is no one here to consult.");
  260.         return 0;
  261.     } else if (!oracl->mpeaceful) {
  262.         pline("The Oracle is in no mood for consultations.");
  263.         return 0;
  264.     } else if (!u.ugold) {
  265.         You("have no money.");
  266.         return 0;
  267.     }
  268.  
  269.     Sprintf(qbuf,
  270.         "\"Wilt thou settle for a minor consultation?\" (%d zorkmids)",
  271.         minor_cost);
  272.     switch (ynq(qbuf)) {
  273.         default:
  274.         case 'q':
  275.         return 0;
  276.         case 'y':
  277.         if (u.ugold < (long)minor_cost) {
  278.             You("don't even have enough money for that!");
  279.             return 0;
  280.         }
  281.         u_pay = minor_cost;
  282.         break;
  283.         case 'n':
  284.         if (u.ugold <= (long)minor_cost ||    /* don't even ask */
  285.             (oracle_cnt == 1 || oracle_flg < 0)) return 0;
  286.         Sprintf(qbuf,
  287.             "\"Then dost thou desire a major one?\" (%d zorkmids)",
  288.             major_cost);
  289.         if (yn(qbuf) != 'y') return 0;
  290.         u_pay = (u.ugold < (long)major_cost ? (int)u.ugold
  291.                             : major_cost);
  292.         break;
  293.     }
  294.     u.ugold -= (long)u_pay;
  295.     oracl->mgold += (long)u_pay;
  296.     flags.botl = 1;
  297.     add_xpts = 0;    /* first oracle of each type gives experience points */
  298.     if (u_pay == minor_cost) {
  299.         outrumor(1, FALSE);
  300.         if (!u.uevent.minor_oracle)
  301.             add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10);
  302.             /* 5 pts if very 1st, or 2 pts if major already done */
  303.         u.uevent.minor_oracle = TRUE;
  304.     } else {
  305.         boolean cheapskate = u_pay < major_cost;
  306.         outoracle(cheapskate);
  307.         if (!cheapskate && !u.uevent.major_oracle)
  308.             add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10);
  309.             /* ~100 pts if very 1st, ~40 pts if minor already done */
  310.         u.uevent.major_oracle = TRUE;
  311.         exercise(A_WIS, !cheapskate);
  312.     }
  313.     if (add_xpts) {
  314.         more_experienced(add_xpts, u_pay/50);
  315.         newexplevel();
  316.     }
  317.     return 1;
  318. }
  319.  
  320. /*rumors.c*/
  321.